package service

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/lzppppppp/virapaksa-go/internal/system_monitor/middleware"
	"github.com/lzppppppp/virapaksa-go/internal/system_monitor/model"
	"github.com/lzppppppp/virapaksa-go/internal/system_monitor/repository"
	"github.com/spf13/viper"
)

/*
 * 接收前端POST方法传送过来的查看CMDB需求
 * 解析数据，返回相应的数据内容
 */
func PostCmdbData(context *gin.Context) {

	// 1. 接收前端数据，并作断言转换数据结构
	var param map[string]interface{}
	err := context.BindJSON(&param)
	if err != nil {
		context.JSON(500, gin.H{"err": err})
		return
	}

	if param["token"] != viper.GetString("token") { // token处理
		log.Printf("INFO: Authentication failed to get CMDB data.\n")
		context.JSON(500, "Error: Authentication failed")
		return
	}

	paramVal, ok := param["param"].(map[string]interface{})
	if !ok {
		log.Printf("ERROR: Get CMDB data, assertion failed.\n") // 处理断言失败的情况
	}

	varArr := []string{"source", "short_name", "ip", "datacenter", "resource_pool", "online_time", "node_exporter", "sys_process_exporter",
		"process_exporter", "port_exporter", "zabbix_agent", "bppm_agent", "scom_agent", "bdops_agent"}

	// 2. 根据前端数据获取CMDB数据
	var isEmpty bool = true // 判断前端的post数据是否为空
	for _, v := range paramVal {
		if v != "" {
			isEmpty = false
			break
		}
	}
	DB := repository.GetDB()
	var selfdefinSearchData []model.CmdbAllServer

	if isEmpty { // 若前端post的数据为空，则将所有CMDB数据返回
		if err := DB.Table("cmdb_all_servers").Find(&selfdefinSearchData).Error; err != nil {
			log.Printf("ERROR: Database fetch failed, error: %v\n", err)
		}
	} else { // 若前端post数据不为空，则返回相应查询条件的数据
		if paramVal["online_time"] != "" {
			urlData := model.FuncVar{
				IP:   viper.GetString("es.host"),
				Port: viper.GetString("es.port"),
				API:  viper.GetString("es.index.menu") + "/_doc/" + paramVal["online_time"].(string) + "/_source",
			}
			response := middleware.GetData(urlData)
			body, _ := io.ReadAll(response.Body)
			var batchData map[string]interface{}
			if err := json.Unmarshal(body, &batchData); err != nil {
				log.Printf("conver to json failed")
			}
			paramVal["online_time"] = batchData["name"].(string)
		}

		var queryData []interface{}
		var whereVar string

		dcMap := map[string]string{
			"nm":    "内蒙数据中心",
			"pek":   "北京数据中心",
			"hf":    "合肥数据中心",
			"sh":    "上海数据中心",
			"xa":    "西安数据中心",
			"nm-zj": "内蒙数据中心-和林",
		}

		for _, value := range varArr { // 组合数据库查询参数
			if paramVal[value] != "" && value != "ip" && value != "datacenter" {
				whereVar = whereVar + value + " = ? AND "
				queryData = append(queryData, paramVal[value])
			} else if paramVal[value] != "" && value == "ip" {
				if paramVal[value] == "-" {
					whereVar = whereVar + value + " <> ? AND "
					queryData = append(queryData, "")
				} else {
					whereVar = whereVar + value + " IN (?) AND "
					ipArr := strings.Split(paramVal[value].(string), "|")
					queryData = append(queryData, ipArr)
				}
			} else if paramVal[value] != "" && value == "datacenter" {
				whereVar = whereVar + value + " = ? AND "
				queryData = append(queryData, dcMap[paramVal[value].(string)])
			}
		}
		whereVarSplit := whereVar[:len(whereVar)-5]
		if err := DB.Table("cmdb_all_servers").Where(whereVarSplit, queryData...).Find(&selfdefinSearchData).Error; err != nil {
			log.Printf("ERROR: Database fetch failed, error: %v\n", err)
		}
	}

	// 3. 处理分页参数，按照分页参数返回前端
	intPageSize := int(param["page_size"].(float64))
	if err != nil {
		log.Printf("ERROR: Convert to int failed, error: %v", err)
		return
	}
	intCurrentPage := int(param["current_page"].(float64))
	if err != nil {
		log.Printf("ERROR: Convert to int failed, error: %v", err)
		return
	}
	totalRow := len(selfdefinSearchData) // 该变量会传递到前端

	var selfdefinDataPage []model.CmdbAllServer

	if intPageSize*intCurrentPage > totalRow { // 获取当前页面对应的数据
		selfdefinDataPage = selfdefinSearchData[intPageSize*(intCurrentPage-1) : totalRow]
	} else {
		selfdefinDataPage = selfdefinSearchData[intPageSize*(intCurrentPage-1) : intPageSize*intCurrentPage]
	}

	if intPageSize*intCurrentPage > totalRow { // 获取当前页面对应的数据
		selfdefinDataPage = selfdefinSearchData[intPageSize*(intCurrentPage-1) : totalRow]
	} else {
		selfdefinDataPage = selfdefinSearchData[intPageSize*(intCurrentPage-1) : intPageSize*intCurrentPage]
	}

	type jsonData struct {
		Code     int
		TotalRow int
		Param    []model.CmdbAllServer
	}
	data := jsonData{ // 返回前端信息
		Code:     200,
		TotalRow: totalRow,
		Param:    selfdefinDataPage,
	}
	context.JSON(http.StatusOK, data)
}
